package com.chixing.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chixing.annotation.AutoIdempotent;
import com.chixing.config.RabbitMQConfig;
import com.chixing.entity.*;
import com.chixing.entity.DTO.OrderCancelEarlyDTO;
import com.chixing.entity.DTO.MessageDTO;
import com.chixing.entity.DTO.OrderCreateDTO;
import com.chixing.mapper.*;
import com.chixing.service.IOrdersService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chixing.service.IRoomInventoryService;
import com.chixing.utils.Result;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author smith
 * @since 2025-09-30
 */
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper,Orders>  implements IOrdersService {

    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private HotelMapper hotelMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private RoomtypeMapper roomtypeMapper;
    @Autowired
    private RoomImagesMapper roomImagesMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private IRoomInventoryService roomInventoryService;
    @Autowired
    private RoomInventoryMapper roomInventoryMapper;
    @Autowired
    private OrderCancelRulesMapper orderCancelRulesMapper;
    @Autowired
    private PenaltyMapper penaltyMapper;
    @Autowired
    private MessageMapper messageMapper;
    @Autowired
    private UserMessageMapper userMessageMapper;
    @Autowired
    private OrderExtensionMapper orderExtensionMapper;

    @Override
    public Result getOrderDetail(Long id) {
        Map<String , Object> orderDetailMap = new HashMap<>();
        //查询订单的状态和订单编号
        Orders orders = ordersMapper.selectById(id);
        orderDetailMap.put("orderId",orders.getOrderId());
        orderDetailMap.put("orderStatus",orders.getOrderStatus());
        orderDetailMap.put("orderNumber",orders.getOrderNumber());
        orderDetailMap.put("isComment",orders.getIsComment());
        //查询酒店信息
        Hotel hotel = hotelMapper.selectById(orders.getHotelId());
        orderDetailMap.put("hotelId",hotel.getHotelId());
        orderDetailMap.put("hotelImage",hotel.getHotelImage());
        orderDetailMap.put("hotelName",hotel.getHotelName());
        orderDetailMap.put("hotelAddress",hotel.getCity()+hotel.getCounty()+hotel.getStreet());
        orderDetailMap.put("hotelPhone",hotel.getContactPhone());
        //查询入住信息
        QueryWrapper<OrderDetail> detailQueryWrapper = new QueryWrapper<>();
        detailQueryWrapper.eq("order_id",orders.getOrderId());
        OrderDetail orderDetail = orderDetailMapper.selectOne(detailQueryWrapper);
        orderDetailMap.put("roomQuantity",orderDetail.getRoomQuantity());
        orderDetailMap.put("checkOut",orderDetail.getCheckOut());
        orderDetailMap.put("checkIn",orderDetail.getCheckIn());
        orderDetailMap.put("userName",orderDetail.getUserName());
        orderDetailMap.put("userPhone",orderDetail.getUserPhone());
        orderDetailMap.put("proPrice",orderDetail.getProPrice());
        orderDetailMap.put("orderPrice",orderDetail.getOrderPrice());
        orderDetailMap.put("roomtypeId",orderDetail.getRoomtypeId());
        //查询房间信息
        Roomtype roomtype = roomtypeMapper.selectById(orderDetail.getRoomtypeId());
        orderDetailMap.put("roomtypeName",roomtype.getRoomtypeName());
        orderDetailMap.put("roomtypeDes",roomtype.getRoomtypeDes());
        orderDetailMap.put("roomArea",roomtype.getRoomArea());
        orderDetailMap.put("roomtypePrice",roomtype.getRoomtypePrice());
        QueryWrapper<RoomImages> imagesQueryWrapper = new QueryWrapper<>();
        imagesQueryWrapper.eq("roomtype_id",orderDetail.getRoomtypeId());
        RoomImages roomImages = roomImagesMapper.selectOne(imagesQueryWrapper);
        orderDetailMap.put("roomImage",roomImages.getImageAddress());
        //查询延迟退房信息，可能为空
        QueryWrapper<OrderExtension> orderExtensionQueryWrapper = new QueryWrapper<>();
        orderExtensionQueryWrapper.eq("order_id" , orders.getOrderId());
        OrderExtension orderExtension = orderExtensionMapper.selectOne(orderExtensionQueryWrapper);
        //将延迟退房的信息放到map中
        orderDetailMap.put("extension",orderExtension);

        if (orderDetailMap!=null)
            return Result.getSuccess(orderDetailMap);
        return Result.getFail(null);
    }

       //
    @Override
    public Result updateStatus(Long orderId, String orderStatus) {
        UpdateWrapper<Orders> wrapper = new UpdateWrapper<>();
        wrapper.eq("order_id",orderId).set("order_status",orderStatus);
        int rows = ordersMapper.update(wrapper);
        if( rows > 0)
            return Result.getSuccess(orderId);
        return Result.getFail(orderId);
    }

    @Override
    public Result getById(Long orderId) {

        Orders orders = ordersMapper.selectById(orderId);

        if(orders != null)
            return Result.getSuccess(orders);
        return Result.getFail(orderId);
    }

    @Override
    public Result getByOrderNumber(String orderNum) {
        QueryWrapper<Orders> wrapper = new QueryWrapper<>();
        wrapper.eq("order_number",orderNum);
        Orders myorder = ordersMapper.selectOne(wrapper);
        if(myorder != null)
            return Result.getSuccess(myorder);
        return Result.getFail(null);
    }

    @Override
    public Result getByPageAndStatus(Integer userId, String orderStatus, Integer pageNum) {
            // 每页显示条数（你可以根据需要修改）
            int pageSize = 2;
            Page<Orders> page = new Page<>(pageNum, pageSize);

            // 构建查询条件
            QueryWrapper<Orders> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userId);
            if (orderStatus != null && !orderStatus.isEmpty()) {
                wrapper.eq("order_status", orderStatus);
            }
            wrapper.orderByDesc("created_at");

            // 分页查询订单
            IPage<Orders> orderPage = ordersMapper.selectPage(page, wrapper);
            List<Orders> ordersList = orderPage.getRecords();

            List<Map<String, Object>> resultList = new ArrayList<>();

            // 遍历订单构建返回数据
            for (Orders orders : ordersList) {
                Map<String, Object> map = new HashMap<>();

                // 订单基础信息
                map.put("orderId", orders.getOrderId());
                //map.put("orderNumber", orders.getOrderNumber());
                map.put("orderStatus", orders.getOrderStatus());
                map.put("isComment", orders.getIsComment());
                map.put("hotelId", orders.getHotelId());

                // 查询酒店信息
                Hotel hotel = hotelMapper.selectById(orders.getHotelId());
                if (hotel != null) {
                    map.put("hotelName", hotel.getHotelName());
                    map.put("hotelAddress", hotel.getCity() + hotel.getCounty() + hotel.getStreet());
                    //map.put("hotelImage", hotel.getHotelImage());
                }

                // 查询入住详情
                QueryWrapper<OrderDetail> detailWrapper = new QueryWrapper<>();
                detailWrapper.eq("order_id", orders.getOrderId());
                OrderDetail orderDetail = orderDetailMapper.selectOne(detailWrapper);
                if (orderDetail != null) {
                    map.put("checkIn", orderDetail.getCheckIn());
                    map.put("checkOut", orderDetail.getCheckOut());
                    map.put("userName", orderDetail.getUserName());
                    //map.put("proPrice", orderDetail.getProPrice());
                    map.put("orderPrice", orderDetail.getOrderPrice());

                    // 查询房型信息
                    Roomtype roomtype = roomtypeMapper.selectById(orderDetail.getRoomtypeId());
                    if (roomtype != null) {
                        map.put("roomtypeName", roomtype.getRoomtypeName());
                        map.put("roomtypePrice", roomtype.getRoomtypePrice());
                        map.put("roomArea", roomtype.getRoomArea());
                    }

                    // 查询房型图片
//                    QueryWrapper<RoomImages> imgWrapper = new QueryWrapper<>();
//                    imgWrapper.eq("roomtype_id", orderDetail.getRoomtypeId());
//                    RoomImages roomImage = roomImagesMapper.selectOne(imgWrapper);
//                    if (roomImage != null) {
//                        map.put("roomImage", roomImage.getImageAddress());
//                    }
                }

                resultList.add(map);
            }

            // 构建分页返回结果
            Map<String, Object> data = new HashMap<>();
            data.put("total", orderPage.getTotal());
            data.put("pageNum", pageNum);
            data.put("pageSize", pageSize);
            data.put("orders", resultList);

            return Result.getSuccess(data);
        }



    @Override
    public Result getOrderDetails(Long orderId) {
        Map<String,Object> map = new HashMap<>();
        // 1. 订单 order (有商品快照)
        Orders orders  = ordersMapper.selectById(orderId);
        map.put("orderNumber",orders.getOrderNumber());
        map.put("orderCreateTime",orders.getCreatedAt());
        map.put("orderStatus",orders.getOrderStatus());
        map.put("productName",orders.getHotelId());
        System.out.println("查询的订单的详情是：" + map);
        return Result.getSuccess(map);
    }

    @Override
    public Result getByOrderId(Long orderId) {
        String orderKey = "order_" + orderId;
        String detailKey = "orderDetail_" + orderId;
        //先判断Redis中是否有该订单
        if (redisTemplate.hasKey(orderKey)){
            System.out.println("Redis中有该订单，直接返回");
            Orders order = (Orders) redisTemplate.opsForValue().get(orderKey);
            List<OrderDetail> orderDetails = (List<OrderDetail>) redisTemplate.opsForValue().get(detailKey);
            Map<String,Object> result = new HashMap<>();
            result.put("order",order);
            result.put("orderDetails",orderDetails);
            return Result.getSuccess(result);
        } else{ //Redis中没有该订单
            System.out.println("Redis中没有该订单，执行MySQL查询");
            Orders order = ordersMapper.selectById(orderId);
            List<OrderDetail> orderDetails = orderDetailMapper.selectList(
                    new QueryWrapper<OrderDetail>().eq("order_id", orderId)
            );

            if (order != null && orderDetails != null){
                //将查询到的数据保存一份在Redis中
                redisTemplate.opsForValue().set(orderKey,order,15, TimeUnit.MINUTES);
                redisTemplate.opsForValue().set(detailKey,orderDetails,15,TimeUnit.MINUTES);

                Map<String,Object> result = new HashMap<>();
                result.put("order",order);
                result.put("orderDetails",orderDetails);
                return Result.getSuccess(result);
            }
            return Result.getFail("订单不存在...");

        }
    }


    @Override
    @AutoIdempotent //验证幂等性
    @Transactional //保证订单主表和订单详情表的事务一致性
    public Result createOrder(OrderCreateDTO orderCreateDTO) {

        System.out.println("正在生成订单");

        //取订单详情
        List<OrderDetail> orderDetails = orderCreateDTO.getOrderDetails();
        OrderDetail detail = orderDetails.get(0); //一般都是用的单房型订单

        Long hotelId = orderCreateDTO.getOrders().getHotelId();
        Long roomTypeId = detail.getRoomtypeId();
        Date checkIn = Date.from(detail.getCheckIn().atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date checkOut = Date.from(detail.getCheckOut().atStartOfDay(ZoneId.systemDefault()).toInstant());

        //尝试扣减库存（Redis + DB）
        Result stockResult = roomInventoryService.decrCount(hotelId, checkIn, checkOut, roomTypeId);
        System.out.println("尝试扣减库存的返回值：getCode = " + stockResult.getCode());
        if (stockResult.getCode() != 200){
            //扣减失败，不生成订单
            return Result.getFail("库存不足");
        }

        //生成订单号
        String orderNumber = UUID.randomUUID().toString().replace("-","");

        //添加order 对象
        Orders order = new Orders();
        order.setOrderNumber(orderNumber);
        order.setHotelId(orderCreateDTO.getOrders().getHotelId());
        order.setUserId(orderCreateDTO.getOrders().getUserId());
        order.setOrderStatus("待支付");
        order.setCreatedAt(LocalDateTime.now());
        order.setIsComment(0);

        //保存order
        this.save(order);
        Double orderPrice = null;
        //添加订单详情
        for (OrderDetail orderDetail : orderDetails){
            orderDetail.setOrderId(order.getOrderId());
            orderPrice = orderDetail.getOrderPrice();
            orderDetailMapper.insert(orderDetail);
        }

        //再写入一份放进Redis中(方便超时取消)
        String orderKey = "order_" + order.getOrderId();
        String detailKey = "orderDetail_" + order.getOrderId();

        redisTemplate.opsForValue().set(orderKey,order);
        redisTemplate.opsForValue().set(detailKey,orderDetails);

        //设置过期时间15mins
        redisTemplate.expire(orderKey,15, TimeUnit.MINUTES);
        redisTemplate.expire(detailKey,15, TimeUnit.MINUTES);

        //发送延迟消息到RabbitMQ(时间一到自动检查是否支付)
        rabbitTemplate.convertAndSend(
                RabbitMQConfig.ORDER_EXCHANGE,
                RabbitMQConfig.ORDER_ROUTING_KEY,
                order.getOrderId()  //传订单id
        );

        // 构建前端需要的返回对象
        // 返回标准JSON对象
        Map<String, Object> data = new HashMap<>();
        data.put("orderId", order.getOrderId());
        data.put("orderNumber", order.getOrderNumber());
        data.put("orderPrice", orderPrice);
        System.out.println("自增生成的orderId = " + order.getOrderId());

        //作为生产者要将消息保存到数据库，并传到MQ
        //从message表中查询出要发送的信息
        Message message = messageMapper.selectById(1);//酒店预定成功的消息
        //把信息存到数据库
        UserMessage userMessage = new UserMessage();
        userMessage.setMessageId(message.getMessageId());
        userMessage.setUserId(orderCreateDTO.getOrders().getUserId());
        userMessage.setStatus("UNREAD");
        userMessage.setIsPushed(0);
        userMessage.setCreatedAt(LocalDateTime.now());
        userMessage.setOrderId(order.getOrderId());
        userMessageMapper.insert(userMessage);
        //把消息封装成messageDTO对象，发送到MQ
        MessageDTO messageDTO = new MessageDTO();
        messageDTO.setId(userMessage.getId());
        messageDTO.setUserId(orderCreateDTO.getOrders().getUserId());
        messageDTO.setOrderNumber(orderNumber);
        messageDTO.setTitle(message.getTitle());
        messageDTO.setContent(message.getContent());
        messageDTO.setType(message.getType());
        messageDTO.setSendTime(LocalDateTime.now());
        //将消息发送到队列
        // 先创建CorrelationData，携带userMessage的ID作为唯一标识
        CorrelationData correlationData = new CorrelationData(userMessage.getId().toString());
        rabbitTemplate.convertAndSend("order.exchange","order.success",messageDTO,correlationData);
        return Result.saveSuccess(data);
    }
    /**
     * 取消待支付订单（核心实现）
     * 1. 校验订单归属与状态（仅待支付可取消）
     * 2. 回退库存锁（locked_count-1，恢复可用库存）
     * 3. 更新订单状态为“已取消”
     * 4. 清理Redis缓存
     */
    @Override
    @Transactional
    public Result cancelUnpaidOrder(Long orderId, Integer userId) {
        // 1️ 查询订单
        Orders order = ordersMapper.selectById(orderId);
        if (order == null) {
            return Result.getFail("订单不存在");
        }

        // 2️ 确认状态是待支付
        if (!"待支付".equals(order.getOrderStatus())) {
            return Result.getFail("订单状态不是待支付，无法取消");
        }

        // 3️ 查询订单详情（每个房型都要回滚库存）
        List<OrderDetail> orderDetails = orderDetailMapper.selectList(
                new QueryWrapper<OrderDetail>().eq("order_id", orderId)
        );

        // 4️ 遍历订单详情，恢复库存
        for (OrderDetail detail : orderDetails) {
            // 原始 LocalDate
            LocalDate checkIn = detail.getCheckIn();
            LocalDate checkOut = detail.getCheckOut();
            //  Redis 用时间戳生成 key（这里转 Date 只用于生成 key，不影响 LocalDate）
            Date checkInDate = Date.from(checkIn.atStartOfDay(ZoneId.systemDefault()).toInstant());
            Date checkOutDate = Date.from(checkOut.atStartOfDay(ZoneId.systemDefault()).toInstant());

            //  Redis key 保持一致：保持与扣库存时的 key 完全一致
            String roomCountKey = "room_count_" + order.getHotelId() + "_" + detail.getRoomtypeId() + "_"
                    + checkInDate.getTime() + "_" + checkOutDate.getTime();


            // Redis 库存 +1
            redisTemplate.opsForValue().increment(roomCountKey);

            // MySQL 库存回滚（减少锁定库存）MySQL 用 LocalDate（与 Mapper 匹配）

            roomInventoryMapper.decreaseLockedCount(order.getHotelId(),
                    detail.getRoomtypeId(), checkIn, checkOut);
        }

        // 5️ 修改订单状态为已取消
        order.setOrderStatus("已取消");
        this.updateById(order);

        // 6️ 删除 Redis 中的订单缓存（如果有）
        redisTemplate.delete("order_" + orderId);

        return Result.updateSuccess("订单已取消，库存已回滚");

    }

    @Override
    @Transactional
    public Result orderCancelEarly(Long orderId) {

        //获取订单
        Orders order = ordersMapper.selectById(orderId);
        //获取订单详情
        OrderDetail orderDetail = orderDetailMapper.selectOne(
                new QueryWrapper<OrderDetail>().eq("order_id",orderId));
        if (order == null){
            return Result.getFail("订单不存在");
        }
        //判断订单状态 - - - ！待入住
        if (!"待入住".equals(order.getOrderStatus())){
            return Result.getFail("订单不可取消");
        }
        //计算当前时间距离入住的时间差
        LocalDate checkIn = orderDetail.getCheckIn();
        LocalDate now = LocalDate.now(ZoneId.of("Asia/Shanghai"));
        long betweenDays = ChronoUnit.DAYS.between(now, checkIn);
        Double backPrice; //订单取消需要退款金额
        Long cancelId = 1L; //默认的为三天前取消
        Double feeRate = 0.0; //默认的违约金额比例为
        String penaltyDesc = ""; //违约描述

        //查询到数据库的取消规则
        List<OrderCancelRules> cancelRules = orderCancelRulesMapper.selectList(
                new QueryWrapper<OrderCancelRules>().orderByDesc("cancel_days")
        );
        //根据时间差去匹配取消规则
        for (OrderCancelRules rule : cancelRules){
            if (betweenDays >= rule.getCancelDays()){
                feeRate = rule.getFeeRate();
                cancelId = rule.getCancelId();
                penaltyDesc = rule.getRuleDesc();
                break;
            }
        }
        //计算退还用户的金额
        backPrice =  orderDetail.getOrderPrice() * (1 - feeRate);
        //计算违约金
        Double penaltyAmount = orderDetail.getOrderPrice() * feeRate;


        //封装消息
        Map<String,Object> msg = new HashMap<>();
        msg.put("orderId",orderId);
        msg.put("orderPrice",orderDetail.getOrderPrice());
        msg.put("cancelId",cancelId);
        msg.put("penaltyAmount",penaltyAmount);
        msg.put("backPrice",backPrice);
        msg.put("penaltyDesc",penaltyDesc);

        //发送消息到RabbitMQ
        rabbitTemplate.convertAndSend(
                RabbitMQConfig.CANCEL_ORDER_EXCHANGE,
                RabbitMQConfig.CANCEL_ORDER_ROUTING_KEY,
                msg
        );

        // 返回结果
        Map<String,Object> data = new HashMap<>();
        data.put("orderId",orderId);
        data.put("orderNumber",order.getOrderNumber());
        data.put("reason","提前退房，不住了，爷不伺候了");
        data.put("backPrice",backPrice);

        return Result.cancelSuccess(data);
    }


}
